package goim

import (
	"bufio"
	"fmt"
	"net"

	"gitee.com/zhangxinzx/im-related/pkg/encoding/binary"
)

//Decoder interface implementaion assertion
var _ Decoder = (*decoder)(nil)

type Decoder interface {
	Read() (*Proto, error)
}

type decoder struct {
	reader *bufio.Reader
}

func NewGoimDecoder(conn net.Conn) Decoder {
	return &decoder{reader: bufio.NewReader(conn)}
}

func (dec *decoder) Read() (*Proto, error) {
	var (
		bodyLen   int
		headerLen int16
		packLen   int32
		buf       []byte
		err       error
	)

	if buf, err = dec.reader.Peek(_rawHeaderSize); err != nil {
		return nil, err
	}

	_, err = dec.reader.Discard(_rawHeaderSize)
	if err != nil {
		return nil, err
	}

	p := &Proto{}
	packLen = binary.BigEndian.Int32(buf[_packOffset:_headerOffset])
	headerLen = binary.BigEndian.Int16(buf[_headerOffset:_verOffset])
	p.Ver = int32(binary.BigEndian.Int16(buf[_verOffset:_opOffset]))
	p.Op = OpType(binary.BigEndian.Int32(buf[_opOffset:_seqOffset]))
	p.Seq = binary.BigEndian.Int32(buf[_seqOffset:])
	if packLen > _maxPackSize {
		return nil, fmt.Errorf("goim: packet len [ %d ] greater than max packet size [ %d]", packLen, _maxPackSize)
	}
	if headerLen != _rawHeaderSize {
		return nil, fmt.Errorf("goim: packet decoder header len [ %d ] should len [ %d]", headerLen, _rawHeaderSize)
	}

	if bodyLen = int(packLen - int32(headerLen)); bodyLen > 0 {
		p.Body, err = dec.reader.Peek(bodyLen)
		_, err = dec.reader.Discard(bodyLen)
	} else {
		p.Body = nil
	}

	return p, err
}
